/*********************************************************************************
 *      Copyright:  (C) 2022 Zhukaifa (928085237@qq.com)
 *                  All rights reserved.
 *
 *       Filename:  4G_dial_up.c
 *    Description:  This file is used to use DIal-up Internet instead of wired or wireless Internet

 *                 
 *        Version:  1.0.0(19/07/22)
 *         Author:  Nbiot <lingyun@gail.com>
 *      ChangeLog:  1, Release initial version on "19/07/22 11:32:46"
 *                 
 ********************************************************************************/

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <libgen.h>
#include <stdlib.h>
#include<getopt.h>

#include "parse_data.h"
#include "com_func.h"
#include "at_cmd.h"
#include "logger.h"
#include "route_opt.h"
#include "thread_init.h"

#define APN_XML "../src/apns-full-conf.xml"

int g_stop = 0;
void sig_stop(int signum)//如果传的参数是信号1，SIGUSR1则停止循环
{
	if(SIGINT == signum)
	{
		log_info("catch the signal:%d\n", signum);
		g_stop = 1;
	}
}
/*静态内联函数*/
static inline void print_usage(char *progname)
{
	printf("Usage:%s [option]...\n", progname);

	printf("%s is a socket server program, which used to verify client and echo back string from it\n", progname);
	printf("\n Mandatory arguments to long options are mandatory for short options too:\n");
	printf("-b(daemon)set progname runing on background\n");
 	printf("-p(--path):sepcify path to open tty.\n");
 	printf("-s(--stop_bit):sepcify bite to stop.\n");
 	printf("-u(--baudrate):sepcify baudrate.\n");
 	printf("-d--data_bit):sepcify bite to data  .\n");
 	printf("-c--check_bit):sepcify bite to check  .\n");
	printf("-h(--hellp):print this help information.\n");
	printf("\n Example:%s -b -p 8900\n", progname);
	return ;
}




int main(int argc, char **argv)
{

	int            rv;
	comport_t      comport;
	cna_t          cna;
	struct termios old_termios;
	int            opt;
	int            daemon_run;
	int            baudrate;
	int            stop_bit;
	int            data_bit;
	int            pack_rate;
	char          *check_bit=NULL;
	char          *path=NULL;
	char          *progname=NULL;
	int            min_metric;


	pthread_attr_t thread_attr;
	pthread_t      tid;

	iface_lock_t   iface_lock;


	memset(&iface_lock, 0, sizeof(&iface_lock));
	memset(&cna, 0, sizeof(struct mccmcnapn_s));
/* interface lock struct inital*/
	iface_lock.eth0_flag=enable;
	iface_lock.wwan0_flag=disable;
	iface_lock.ppp0_flag=disable;

	pthread_mutex_init(&iface_lock.lock, NULL);

	signal(SIGINT, sig_stop);//set sigusr1 for sig_stop as args
	struct option                    long_options[] = 
	{

		{"dameon", no_argument, NULL, 'b'},
		{"path", required_argument,NULL, 'p'},
		{"baudrate", required_argument, NULL, 'u'},
		{"data_bit", required_argument, NULL, 'd'},
		{"check_bit", no_argument, NULL, 'c'},
		{"stop_bit",required_argument, NULL, 's'},
	
		{ NULL, 0, NULL, 0}

	};

	progname = basename(argv[0]);
	memset(&comport, 0, sizeof(&comport));
                                                           

	while((opt = getopt_long(argc, argv,"bn:u:d:p:s:f:h", long_options, NULL)) != -1)
	{
		switch(opt)
		{
			case 'b':
				daemon_run=1;
				break;
		                        
			case 'n':
				comport.fname=optarg;
				break;         

			case 'u':
				comport.baud_rate=atoi(optarg);//char -> int
				break;

			case 'd':
				comport.data_bits=atoi(optarg);
				break;

			case 'p':
		
				comport.parity=*optarg;
				break;

			case 's':
				comport.stop_bits=atoi(optarg);
				break;

			case 'f':
				comport.flow_ctrl=atoi(optarg);
				break;

			case 'h':
				print_usage(progname);
				return EXIT_SUCCESS;

			default:
				break;
		}
	}
	if( !comport.fname )
	{
		print_usage(progname);
		return -1;
	}

	if(daemon_run)//set dameon run
	{
		daemon(0, 0);
	}

	if(logger_init("./serial.log", LOG_LEVEL_INFO) <0)
	{
		fprintf(stderr, "inital logger system failure:%s\n", strerror(errno));	
		return -2;
	}
	log_info("logger_init() successsful!\n");


	if((comport.fd=com_open(comport.fname))<0)
	{
		log_error("com_open() failure:%s!\n", strerror(errno));

		com_close(&comport);
		return -6;
	}

	if(com_init(&comport)<0)
	{
		log_error("com_init() failure:%s\n", strerror(errno));

		com_close(&comport);
		return -7;
	}


	iface_lock.min_metric= route_get_min_metric();
	if( iface_lock.min_metric<0 )
	{
		log_error("%s failure:%s!\n", __func__, strerror(errno));

		return -3;
	}
	log_info("iface_lock.min_metric() successsful!\n");


	rv=thread_init(&thread_attr);
	if( rv<0 )
	{
		log_error("%s failure:%s!\n", __func__, strerror(errno));
		return -4;
	}

	pthread_create(&tid, &thread_attr, thread_eth0,(void *) &iface_lock);
	log_info("Pthread create eth0 tid[%ld] successsfully\n", tid);//long type ld

	pthread_create(&tid, &thread_attr, thread_wwan0,(void *) &iface_lock);
	log_info("Pthread create wwan0 tid[%ld] successsfully\n", tid);//long type ld


	while(!g_stop)
	{
		
		rv=pthread_mutex_lock(&iface_lock.lock);
		if( rv!=0 )
		{
			log_error("%s failure:%s!\n", __func__, strerror(errno));

			return -5;
		}


		log_info("thread [ppp0] start running and lock on !!!\n");

		if(iface_lock.ppp0_flag==enable)
		{
			log_info("Start Dial-up............\n");
			if(route_exist("ppp0")!=0)//ppp0 not exist
			{
				log_warn("iface[ppp0] is not exist\n");

				rv=check_sim_allready(&comport);
				if( rv<0 )
				{
					log_error("%s failure:%s!\n", __func__, strerror(errno));

					com_close(&comport);
					return -8;
				}

				rv=parse_mccmnc(&comport, &cna);
				if( rv<0 )
				{
					log_error("%s failure:%s!\n", __func__, strerror(errno));

					com_close(&comport);
					return -9;
				}


				parse_apn(APN_XML, &cna);
				if( cna.apn==NULL )
				{
					log_error("%s failure:%s!\n", __func__, strerror(errno));

					com_close(&comport);
					return -10;
				}

				/*中国移动：cmnet。中国联通：3gnet。中国电信：ctnet。*/

				rv=set_apn(&comport, &cna);
				if( rv<0 )
				{
					log_error("%s failure:%s!\n", __func__, strerror(errno));

					com_close(&comport);
					return -11;
				}
				system("sudo pppd call rasppp &");
#if 0
				rv=route_add("ppp0", iface_lock->min_metric);
				if( rv<0 )
				{
					log_error("%s failure:%s!\n", __func__, strerror(errno));
				}
#endif
		
				log_info("Dial-up has been successful and working...... !\n");

			}
		}


		rv=pthread_mutex_unlock(&iface_lock.lock);
		if( rv!=0 )
		{
			log_error("%s failure:%s!\n", __func__, strerror(errno));

			return -11;
		}

		log_info("thread [ppp0] stop running and lock off !!!\n");

		sleep(3);
	}

	pthread_mutex_destroy(&iface_lock.lock);
	log_info("program %s stop running\n", __FILE__);
	logger_term();
	com_close(&comport);
	return 0;

}

void *thread_eth0(void *args)
{


	int             rate;
	int             rv=-1;
	iface_lock_t   *iface_lock;


	iface_lock=(iface_lock_t *)args;


	while(!g_stop)
	{
		
		rv=pthread_mutex_lock(&iface_lock->lock);

		if( rv!=0 )
		{
			log_error("%s failure:%s!\n", __func__, strerror(errno));
		}

		log_info("thread [eth0] start running and lock on !!!\n");



		rate=route_ping("eth0", "baidu.com");
		if( rate<0 )
		{
			log_error("%s failure:%s!\n", __func__, strerror(errno));

		}

		else if(rate==0)
		{
			log_info("The wired network [eth0] is normal!\n");
			if(iface_lock->wwan0_flag==enable)
			{
				log_info("Stopping wireless connection ......\n");
#if 0
				rv=route_del("wwan0", iface_lock->min_metric);
				if( rv<0 )
				{
					log_error("%s failure:%s!\n", __func__, strerror(errno));

				}
#endif
				iface_lock->wwan0_flag=disable;
			}

			if(iface_lock->ppp0_flag==enable)
			{
				log_info("Stopping dial-up ......\n");
#if 0
				rv=route_del("ppp0", iface_lock->min_metric);
				if( rv<0 )
				{
					log_error("%s failure:%s!\n", __func__, strerror(errno));

				}
#endif
				rv=route_kill_process("pppd");
				if( rv<0 )
				{
					log_error("%s failure:%s!\n", __func__, strerror(errno));

				}

				iface_lock->ppp0_flag=disable;
			}
			
			iface_lock->eth0_flag=enable;
			log_info("Using wired[eth0] Internet[successsful]\n");
	
		}
		else
		{
			log_info("Try switching to a wireless network connection\n");
			iface_lock->eth0_flag=disable;
			iface_lock->wwan0_flag=enable;
		}

		
		rv=pthread_mutex_unlock(&iface_lock->lock);
		if( rv!=0 )
		{
			log_error("%s failure:%s!\n", __func__, strerror(errno));

		}

		log_info("thread [eth0] stop running and lock off !!!\n");

		sleep(3);
	}
	pthread_exit(NULL);

}


void *thread_wwan0(void *args)
{


	int             rate;
	int             rv=-1;
	iface_lock_t   *iface_lock;


	iface_lock=(iface_lock_t *)args;


	while(!g_stop)
	{
		
		rv=pthread_mutex_lock(&iface_lock->lock);
		if( rv!=0 )
		{
			log_error("%s failure:%s!\n", __func__, strerror(errno));

		}

		log_info("thread [wwan0] start running and lock on !!!\n");


		rate=route_ping("wwan0", "baidu.com");
		if(rate==0)
		{
			log_info("The wireless[wwan0] is normal!\n");
			if(!iface_lock->eth0_flag || iface_lock->ppp0_flag)
			{
				if(iface_lock->ppp0_flag==enable)
				{
					rv=route_del("ppp0", iface_lock->min_metric);
					if( rv<0 )
					{
						log_error("%s failure:%s!\n", __func__, strerror(errno));
					}

					rv=route_kill_process("pppd");
					if( rv<0 )
					{
						log_error("%s failure:%s!\n", __func__, strerror(errno));
					}

					iface_lock->ppp0_flag=disable;
				}
#if 0
				rv=route_add("wwan0", iface_lock->min_metric);
				if( rv<0 )
				{
					log_error("%s failure:%s!\n", __func__, strerror(errno));
				}
#endif
				iface_lock->wwan0_flag=enable;
			}

		}
		else
		{
			log_warn("The wireless network is unavailable");
			if(iface_lock->wwan0_flag==enable)
			{
			
				log_info("Try switching to dial-up[ppp0] \n");
				iface_lock->wwan0_flag=disable;
				iface_lock->ppp0_flag=enable;
			}
		}

		rv=pthread_mutex_unlock(&iface_lock->lock);
		if( rv!=0 )
		{
			log_error("%s failure:%s!\n", __func__, strerror(errno));

		}

		log_info("thread [wwan0] stop running and lock off !!!\n");

		sleep(3);
	}
	pthread_exit(NULL);

}
